package com.morpheus.zookeeper.api.lock.single;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;

import org.apache.commons.lang3.StringUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.utils.CloseableUtils;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.morpheus.zookeeper.api.lock.SingleLock;
import com.morpheus.zookeeper.config.ZookeeperProperties;

public class SingleDistributedLock implements SingleLock {
	private static final Logger LOGGER = LoggerFactory.getLogger(SingleDistributedLock.class);
	private static final String SINGLE_LOCK_PATH = "lock/single/lock";
	private static final String SINGLE_LOCK_QUEUE_PATH = "lock/single/queue";

	private ZookeeperProperties zookeeperProperties = null;
	private CuratorFramework curatorFramework = null;
	private InterProcessMutex interProcessMutex = null;
	private String lockName = null;

	public SingleDistributedLock(ZookeeperProperties zookeeperProperties) {
		this.zookeeperProperties = zookeeperProperties;
	}

	private String getLockPath(String lockName) {
		String rootPath = this.zookeeperProperties.getRootPath();
		String lockPath = String.format("%s/%s/%s", rootPath, SINGLE_LOCK_PATH, lockName);
		return lockPath;
	}

	@SuppressWarnings("all")
	private String getLockQueuePath(String lockName) {
		String rootPath = this.zookeeperProperties.getRootPath();
		String lockQueuePath = String.format("%s/%s/%s", rootPath, SINGLE_LOCK_QUEUE_PATH, lockName);
		return lockQueuePath;
	}

	public void init(String lockName) {
		this.lockName = lockName;
		try {
			this.curatorFramework.start();
			this.curatorFramework.create().creatingParentsIfNeeded().withProtection().withMode(CreateMode.PERSISTENT)
					.forPath(this.zookeeperProperties.getRootPath());

			String lockPath = this.getLockPath(lockName);
			this.interProcessMutex = new InterProcessMutex(this.curatorFramework, lockPath);
		} catch (Throwable th) {
			LOGGER.error("SingleDistributedLock.init()	Throwable", th);
			throw new IllegalStateException(th);
		}
	}

	@Override
	public boolean hasLock() {
		try {
			boolean flag = this.interProcessMutex.isAcquiredInThisProcess();
			LOGGER.debug("SingleDistributedLock.hasLock() flag={}", flag);
			return flag;
		} catch (Throwable th) {
			LOGGER.error("ZkDistributeLock.hasLock() Throwable", th);
		}
		return false;
	}

	@Override
	public void lock() {
		try {
			this.interProcessMutex.acquire();
		} catch (Throwable th) {
			LOGGER.error("SingleDistributedLock.lock() throwable", th);
			throw new IllegalStateException(th);
		}
	}

	@Override
	public void lock(long time, TimeUnit unit) throws InterruptedException {
		try {
			boolean flag = this.interProcessMutex.acquire(time, unit);
			LOGGER.debug("SingleDistributedLock.lock() flag={}", flag);
		} catch (Throwable th) {
			LOGGER.error("SingleDistributedLock.lock(time, unit) throwable", th);
			throw new IllegalStateException(th);
		}
	}

	@Override
	public void lockInterruptibly(String lockName) throws InterruptedException {

	}

	@Override
	public Condition newCondition() {

		return null;
	}

	@Override
	public boolean tryLock() {
		try {
			if (!this.interProcessMutex.isAcquiredInThisProcess()) {
				this.interProcessMutex.acquire();
			}
			return true;
		} catch (Throwable th) {
			LOGGER.error("SingleDistributedLock.tryLock() throwable", th);
		} finally {
		}
		return false;
	}

	@Override
	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		try {
			if (!this.interProcessMutex.isAcquiredInThisProcess()) {
				boolean flag = this.interProcessMutex.acquire(time, unit);
				return flag;
			}
		} catch (Throwable th) {
			LOGGER.error("SingleDistributedLock.tryLock(time, unit) throwable", th);
		} finally {
		}
		return false;
	}

	@Override
	public void unlock() {
		try {
			if (this.interProcessMutex.isAcquiredInThisProcess()) {
				this.interProcessMutex.release();
			}
			if (StringUtils.isNotEmpty(this.lockName)) {
				String lockPath = this.getLockPath(lockName);
				Stat stat = this.curatorFramework.checkExists().forPath(lockPath);
				if (stat != null) {
					this.curatorFramework.delete().deletingChildrenIfNeeded().forPath(lockPath);
				}
			}
		} catch (Throwable th) {
			LOGGER.error("SingleDistributedLock.unlock() throwable", th);
			throw new IllegalStateException(th);
		} finally {
			this.destory();
		}
	}

	@Override
	public void destory() {
		CloseableUtils.closeQuietly(this.curatorFramework);
		this.curatorFramework = null;
	}
}
